home *** CD-ROM | disk | FTP | other *** search
/ Inside Multimedia 1994 April / Inside Multimedia CD-ROM (April 1994).iso / prg / gs / gssource.exe / GDEVSVGA.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-24  |  20.1 KB  |  685 lines

  1. /* Copyright (C) 1991, 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevsvga.c */
  21. /* SuperVGA display drivers for Ghostscript */
  22. #include "dos_.h"
  23. typedef union REGS registers;
  24. #include "memory_.h"
  25. #include "gx.h"
  26. #include "gserrors.h"
  27. #include "gxdevice.h"
  28. #include "gdevpcfb.h"
  29. #include "gdevsvga.h"
  30.  
  31. /* The color map for dynamically assignable colors. */
  32. #define first_color_index 64
  33. private int next_color_index;
  34. private ushort dynamic_colors[256 - first_color_index];
  35.  
  36. /* Macro for casting gx_device argument */
  37. #define fb_dev ((gx_device_svga *)dev)
  38.  
  39. /* Procedure records */
  40. #define svga_procs(open) {\
  41.     open, gx_default_get_initial_matrix,\
  42.     gx_default_sync_output, gx_default_output_page, svga_close,\
  43.     svga_map_rgb_color, svga_map_color_rgb,\
  44.     svga_fill_rectangle, gx_default_tile_rectangle,\
  45.     svga_copy_mono, svga_copy_color, gx_default_draw_line,\
  46.     svga_get_bits, gx_default_get_props, gx_default_put_props\
  47. }
  48.  
  49. /* Save the controller mode */
  50. private int svga_save_mode = -1;
  51.  
  52. /* Macro for validating rectangle parameters x and w. */
  53. /* set_pixel_ptr implicitly validates y and h. */
  54. #define validate_rect_x()\
  55.   if ( w <= 0 ) return 0;\
  56.   if ( x < 0 || x + w > dev->width ) return_error(gs_error_rangecheck)
  57.  
  58. /* ------ Internal routines ------ */
  59.  
  60. #define regen 0xa000
  61.  
  62. /* Construct a pointer for writing a pixel. */
  63. /* Assume 64K pages, 64K granularity. */
  64. #define set_pixel_ptr(ptr, fbdev, x, y, wnum)\
  65. {    ulong index = (ulong)(y) * fbdev->raster + (uint)(x);\
  66.     if ( (uint)(index >> 16) != fbdev->page )\
  67.        {    if ( y < 0 || y >= fbdev->height ) return_error(gs_error_rangecheck);\
  68.         (*fbdev->set_page)(fbdev, (fbdev->page = index >> 16), wnum);\
  69.        }\
  70.     ptr = (fb_ptr)MK_PTR(regen, (ushort)index);\
  71. }
  72. #define set_pixel_write_ptr(ptr, fbdev, x, y)\
  73.   set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_write)
  74. #define set_pixel_read_ptr(ptr, fbdev, x, y)\
  75.   set_pixel_ptr(ptr, fbdev, x, y, fbdev->wnum_read)
  76.  
  77. /* Find the graphics mode for a desired width and height. */
  78. /* Set the mode in the device structure and return 0, */
  79. /* or return an error code. */
  80. int
  81. svga_find_mode(gx_device *dev, const mode_info _ds *mip)
  82. {    fb_dev->raster = fb_dev->width;
  83.     for ( ; mip->mode >= 0; mip++ )
  84.     {    if ( mip->width >= fb_dev->width &&
  85.              mip->height >= fb_dev->height
  86.            )
  87.         {    fb_dev->mode = mip;
  88.             gx_device_adjust_resolution(dev, mip->width, mip->height);
  89.             return 0;
  90.         }
  91.     }
  92.     return_error(gs_error_rangecheck);
  93. }
  94.  
  95. /* Set the index for writing into the color DAC. */
  96. #define svga_dac_set_write_index(i) outportb(0x3c8, i)
  97.  
  98. /* Write 6-bit R,G,B values into the color DAC. */
  99. #define svga_dac_write(r, g, b)\
  100.   (outportb(0x3c9, r), outportb(0x3c9, g), outportb(0x3c9, b))
  101.  
  102. /* ------ Common procedures ------ */
  103.  
  104. /* Initialize the device structure and the DACs. */
  105. int
  106. svga_open(gx_device *dev)
  107. {    fb_dev->x_pixels_per_inch =
  108.       fb_dev->y_pixels_per_inch =
  109.         fb_dev->height / 11.0;
  110.     /* Set the display mode. */
  111.     if ( svga_save_mode < 0 )
  112.         svga_save_mode = (*fb_dev->get_mode)();
  113.     (*fb_dev->set_mode)(fb_dev->mode->mode);
  114.     /* Load the color DAC. */
  115.     svga_dac_set_write_index(0);
  116.        {    int c;
  117.         for ( c = 0; c < 64; c++ )
  118.            {    static const byte c2[10] =
  119.                { 0, 42, 0, 0, 0, 0, 0, 0, 21, 63 };
  120.             svga_dac_write(c2[(c >> 2) & 9], c2[(c >> 1) & 9],
  121.                        c2[c & 9]);
  122.            }
  123.        }
  124.     /* Initialize the dynamic color table. */
  125.     next_color_index = first_color_index;
  126.     fb_dev->page = -1;
  127.     return 0;
  128. }
  129.  
  130. /* Close the device; reinitialize the display for text mode. */
  131. int
  132. svga_close(gx_device *dev)
  133. {    if ( svga_save_mode >= 0 )
  134.         (*fb_dev->set_mode)(svga_save_mode);
  135.     svga_save_mode = -1;
  136.     return 0;
  137. }
  138.  
  139. /* Map a r-g-b color to a palette index. */
  140. /* The first 64 entries of the color map are set */
  141. /* for compatibility with the older display modes: */
  142. /* these are indexed as 0.0.R0.G0.B0.R1.G1.B1. */
  143. gx_color_index
  144. svga_map_rgb_color(gx_device *dev, ushort r, ushort g, ushort b)
  145. {
  146. #define cv_bits(v,n) (v >> (gx_color_value_bits - n))
  147.     ushort r5 = cv_bits(r, 5), g5 = cv_bits(g, 5), b5 = cv_bits(b, 5);
  148.     static const byte cube_bits[32] =
  149.        {    0, 128, 128, 128, 128, 128, 128, 128, 128, 128,
  150.         8, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
  151.         1, 128, 128, 128, 128, 128, 128, 128, 128, 128,
  152.         9
  153.        };
  154.     uint cx = ((uint)cube_bits[r5] << 2) + ((uint)cube_bits[g5] << 1) +
  155.           (uint)cube_bits[b5];
  156.     ushort rgb;
  157.     /* Check for a color on the cube. */
  158.     if ( cx < 64 ) return (gx_color_index)cx;
  159.     /* Not on the cube, check the dynamic color table. */
  160.     rgb = (r5 << 10) + (g5 << 5) + b5;
  161.        {    int i = next_color_index - first_color_index;
  162.         register ushort _ds *pdc = dynamic_colors + i;
  163.         while ( --i >= 0 )
  164.           if ( *--pdc == rgb )
  165.             return (gx_color_index)(i + first_color_index);
  166.        }
  167.     /* Not on the cube, and not in the dynamic table. */
  168.     /* Put in the dynamic table if space available. */
  169.     if ( next_color_index < 255 )
  170.        {    int i = next_color_index++;
  171.         dynamic_colors[i - first_color_index] = rgb;
  172.         svga_dac_set_write_index(i);
  173.         svga_dac_write(cv_bits(r, 6), cv_bits(g, 6), cv_bits(b, 6));
  174.         return (gx_color_index)i;
  175.        }
  176.     /* No space left, report failure. */
  177.     return gx_no_color_index;
  178. }
  179.  
  180. /* Map a color code to r-g-b. */
  181. /* This routine must invert the transformation of the one above. */
  182. /* Since this is practically never used, we just read the DAC. */
  183. int
  184. svga_map_color_rgb(gx_device *dev, gx_color_index color, ushort prgb[3])
  185. {    uint cval;
  186.     outportb(0x3c7, (byte)color);
  187. #define dacin() (cval = inportb(0x3c9) >> 1,\
  188.   ((cval << 11) + (cval << 6) + (cval << 1) + (cval >> 4)) >>\
  189.    (16 - gx_color_value_bits))
  190.     prgb[0] = dacin();
  191.     prgb[1] = dacin();
  192.     prgb[2] = dacin();
  193. #undef dacin
  194.     return 0;
  195. }
  196.  
  197. /* Copy a monochrome bitmap.  The colors are given explicitly. */
  198. /* Color = gx_no_color_index means transparent (no effect on the image). */
  199. int
  200. svga_copy_mono(gx_device *dev,
  201.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  202.   int x, int y, int w, int h, gx_color_index czero, gx_color_index cone)
  203. {    register int xi;
  204.     uint skip = fb_dev->raster - w;
  205.     int yi;
  206.     fb_ptr ptr = (fb_ptr)0;
  207.     const byte *srow = base + (sourcex >> 3);
  208.     uint imask = 0x80 >> (sourcex & 7);
  209.     validate_rect_x();
  210. #define izero (int)czero
  211. #define ione (int)cone
  212.     for ( yi = 0; yi < h; yi++ )
  213.        {    const byte *sptr = srow;
  214.         uint bits = *sptr;
  215.         register uint mask = imask;
  216.         if ( PTR_OFF(ptr) <= skip )
  217.             set_pixel_write_ptr(ptr, fb_dev, x, y + yi);
  218.         for ( xi = 0; xi < w; xi++ )
  219.            {    if ( PTR_OFF(ptr) == 0 )
  220.                 set_pixel_write_ptr(ptr, fb_dev, x + xi, y + yi);
  221.             if ( bits & mask )
  222.                {    if ( ione != no_color ) *ptr = (byte)ione;
  223.                }
  224.             else
  225.                {    if ( izero != no_color ) *ptr = (byte)izero;
  226.                }
  227.             if ( !(mask >>= 1) ) mask = 0x80, bits = *++sptr;
  228.             ptr++;
  229.            }
  230.         ptr += skip;
  231.         srow += raster;
  232.        }
  233. #undef izero
  234. #undef ione
  235.     return 0;
  236. }
  237.  
  238. /* Copy a color pixelmap.  This is just like a bitmap, */
  239. /* except that each pixel takes 8 bits instead of 1. */
  240. int
  241. svga_copy_color(gx_device *dev,
  242.   const byte *base, int sourcex, int raster, gx_bitmap_id id,
  243.   int x, int y, int w, int h)
  244. {    int xi, yi;
  245.     int skip = raster - w;
  246.     const byte *sptr = base + sourcex;
  247.     fb_ptr ptr;
  248.     validate_rect_x();
  249.     for ( yi = y; yi - y < h; yi++ )
  250.        {    ptr = 0;
  251.         for ( xi = x; xi - x < w; xi++ )
  252.            {    if ( PTR_OFF(ptr) == 0 )
  253.                 set_pixel_write_ptr(ptr, fb_dev, xi, yi);
  254.             *ptr++ = *sptr++;
  255.            }
  256.         sptr += skip;
  257.        }
  258.     return 0;
  259. }
  260.  
  261. /* Fill a rectangle. */
  262. int
  263. svga_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  264.   gx_color_index color)
  265. {    uint raster = fb_dev->raster;
  266.     ushort limit = (ushort)-raster;
  267.     int yi;
  268.     fb_ptr ptr;
  269.     if ( x < 0 || x + w > dev->width ) return -1;    /* skip w */
  270.     set_pixel_write_ptr(ptr, fb_dev, x, y);
  271.     /* Most fills are very small and don't cross a page boundary. */
  272.     yi = h;
  273.     switch ( w )
  274.        {
  275.     case 0: return 0;        /* no-op */
  276.     case 1:
  277.         while ( --yi >= 0 && PTR_OFF(ptr) < limit )
  278.             ptr[0] = (byte)color,
  279.             ptr += raster;
  280.         if ( !++yi ) return 0;
  281.         break;
  282.     case 2:
  283.         while ( --yi >= 0 && PTR_OFF(ptr) < limit )
  284.             ptr[0] = ptr[1] = (byte)color,
  285.             ptr += raster;
  286.         if ( !++yi ) return 0;
  287.         break;
  288.     case 3:
  289.         while ( --yi >= 0 && PTR_OFF(ptr) < limit )
  290.             ptr[0] = ptr[1] = ptr[2] = (byte)color,
  291.             ptr += raster;
  292.         if ( !++yi ) return 0;
  293.         break;
  294.     case 4:
  295.         while ( --yi >= 0 && PTR_OFF(ptr) < limit )
  296.             ptr[0] = ptr[1] = ptr[2] = ptr[3] = (byte)color,
  297.             ptr += raster;
  298.         if ( !++yi ) return 0;
  299.         break;
  300.     default:
  301.         if ( w < 0 ) return 0;
  302.        }
  303.     while ( --yi >= 0 )
  304.        {    if ( PTR_OFF(ptr) < limit )
  305.            {    memset(ptr, (byte)color, w);
  306.             ptr += raster;
  307.            }
  308.         else if ( PTR_OFF(ptr) <= (ushort)(-w) )
  309.            {    memset(ptr, (byte)color, w);
  310.             if ( yi > 0 )
  311.                 set_pixel_write_ptr(ptr, fb_dev, x, y + h - yi);
  312.            }
  313.         else
  314.            {    uint left = (uint)0x10000 - PTR_OFF(ptr);
  315.             memset(ptr, (byte)color, left);
  316.             set_pixel_write_ptr(ptr, fb_dev, x + left, y + h - 1 - yi);
  317.             memset(ptr, (byte)color, w - left);
  318.             ptr += raster - left;
  319.            }
  320.        }
  321.     return 0;
  322. }
  323.  
  324. /* Read scan lines back from the frame buffer. */
  325. int
  326. svga_get_bits(gx_device *dev, int y, byte *data, uint size, int pad_to_word)
  327. {    /* We don't have to worry about padding, because we read back */
  328.     /* a byte per pixel and the frame buffer width is always */
  329.     /* a multiple of 8 pixels. */
  330.     uint bytes_per_row = dev->width;
  331.     uint count = min(dev->height - y, size / bytes_per_row);
  332.     byte *dest = data;
  333.     ushort limit = (ushort)-bytes_per_row;
  334.     int j;
  335.     for ( j = count; j--; dest += bytes_per_row, y++ )
  336.        {    fb_ptr src;
  337.         set_pixel_read_ptr(src, fb_dev, 0, y);
  338.         /* The logic here is similar to fill_rectangle. */
  339.         if ( PTR_OFF(src) <= limit )
  340.             memcpy(dest, src, bytes_per_row);
  341.         else
  342.            {    uint left = (uint)0x10000 - PTR_OFF(src);
  343.             memcpy(dest, src, left);
  344.             set_pixel_read_ptr(src, fb_dev, left, y);
  345.             memcpy(dest + left, src, bytes_per_row - left);
  346.            }
  347.        }
  348.     return count;
  349. }
  350.  
  351. /* ------ The VESA device ------ */
  352.  
  353. private dev_proc_open_device(vesa_open);
  354. private gx_device_procs vesa_procs = svga_procs(vesa_open);
  355. int vesa_get_mode(P0());
  356. void vesa_set_mode(P1(int));
  357. private void vesa_set_page(P3(gx_device_svga *, int, int));
  358. gx_device_svga gs_vesa_device =
  359.     svga_device(vesa_procs, "vesa", vesa_get_mode, vesa_set_mode, vesa_set_page);
  360.  
  361. /* Define the structures for information returned by the BIOS. */
  362. #define bits_include(a, m) !(~(a) & (m))
  363. /* Information about the BIOS capabilities. */
  364. typedef struct {
  365.     byte vesa_signature[4];        /* "VESA" */
  366.     ushort vesa_version;
  367.     char *product_info;        /* product name string */
  368.     byte capabilities[4];        /* (undefined) */
  369.     ushort *mode_list;        /* supported video modes, -1 ends */
  370. } vga_bios_info;
  371. /* Information about an individual VESA mode. */
  372. typedef enum {
  373.     m_supported = 1,
  374.     m_graphics = 0x10
  375. } mode_attribute;
  376. typedef enum {
  377.     w_supported = 1,
  378.     w_readable = 2,
  379.     w_writable = 4
  380. } win_attribute;
  381. typedef struct {
  382.     ushort mode_attributes;
  383.     byte win_a_attributes;
  384.     byte win_b_attributes;
  385.     ushort win_granularity;
  386.     ushort win_size;
  387.     ushort win_a_segment;
  388.     ushort win_b_segment;
  389.     void (*win_func_ptr)(P2(int, int));
  390.     ushort bytes_per_line;
  391.         /* Optional information */
  392.     ushort x_resolution;
  393.     ushort y_resolution;
  394.     byte x_char_size;
  395.     byte y_char_size;
  396.     byte number_of_planes;
  397.     byte bits_per_pixel;
  398.     byte number_of_banks;
  399.     byte memory_model;
  400.     byte bank_size;
  401.         /* Padding to 256 bytes */
  402.     byte _padding[256-29];
  403. } vesa_info;
  404.  
  405. /* Read the device mode */
  406. int
  407. vesa_get_mode()
  408. {    registers regs;
  409.     regs.h.ah = 0x4f;
  410.     regs.h.al = 0x03;
  411.     int86(0x10, ®s, ®s);
  412.     return regs.rshort.bx;
  413. }
  414.  
  415. /* Set the device mode */
  416. void
  417. vesa_set_mode(int mode)
  418. {    registers regs;
  419.     regs.h.ah = 0x4f;
  420.     regs.h.al = 0x02;
  421.     regs.rshort.bx = mode;
  422.     int86(0x10, ®s, ®s);
  423. }
  424.  
  425. /* Read information about a device mode */
  426. private int
  427. vesa_get_info(int mode, vesa_info _ss *info)
  428. {    registers regs;
  429.     struct SREGS sregs;
  430.     regs.h.ah = 0x4f;
  431.     regs.h.al = 0x01;
  432.     regs.rshort.cx = mode;
  433.     segread(&sregs);
  434.     sregs.es = sregs.ss;
  435.     regs.rshort.di = PTR_OFF(info);
  436.     int86x(0x10, ®s, ®s, &sregs);
  437. #ifdef DEBUG
  438.     if ( regs.h.ah == 0 && regs.h.al == 0x4f )
  439.         dprintf8("vesa_get_info(%x): ma=%x wa=%x/%x wg=%x ws=%x wseg=%x/%x\n",
  440.              mode, info->mode_attributes,
  441.              info->win_a_attributes, info->win_b_attributes,
  442.              info->win_granularity, info->win_size,
  443.              info->win_a_segment, info->win_b_segment);
  444.     else
  445.         dprintf3("vesa_get_info(%x) failed: ah=%x al=%x\n",
  446.              mode, regs.h.ah, regs.h.al);
  447. #endif
  448.     return (regs.h.ah == 0 && regs.h.al == 0x4f ? 0 : -1);
  449. }
  450.  
  451. /* Initialize the graphics mode. */
  452. /* Shared routine to look up a VESA-compatible BIOS mode. */
  453. private int
  454. vesa_find_mode(gx_device *dev, const mode_info _ds *mode_table)
  455. {    /* Select the proper video mode */
  456.     vesa_info info;
  457.     const mode_info _ds *mip;
  458.     for ( mip = mode_table; mip->mode >= 0; mip++ )
  459.        {    if ( mip->width >= fb_dev->width &&
  460.              mip->height >= fb_dev->height &&
  461.              vesa_get_info(mip->mode, &info) >= 0 &&
  462.              bits_include(info.mode_attributes,
  463.             m_supported | m_graphics) &&
  464.              info.win_granularity == 64 &&
  465.              info.win_size == 64 &&
  466.              bits_include(info.win_a_attributes,
  467.             w_supported) &&
  468.              info.win_a_segment == regen
  469.            )
  470.            {    /* Make sure we can both read & write. */
  471.             /* Initialize for the default case. */
  472.             fb_dev->wnum_read = 0;
  473.             fb_dev->wnum_write = 0;
  474.             if ( bits_include(info.win_a_attributes,
  475.                 w_readable | w_writable)
  476.                )
  477.                 break;
  478.             else if ( info.win_b_segment == regen &&
  479.                 bits_include(info.win_b_attributes,
  480.                     w_supported) &&
  481.                 bits_include(info.win_a_attributes |
  482.                     info.win_b_attributes,
  483.                     w_readable | w_writable)
  484.                )
  485.                {    /* Two superimposed windows. */
  486.                 if ( !bits_include(info.win_a_attributes,
  487.                     w_writable)
  488.                    )
  489.                     fb_dev->wnum_write = 1;
  490.                 else
  491.                     fb_dev->wnum_read = 1;
  492.                }
  493.             break;
  494.            }
  495.        }
  496.     if ( mip->mode < 0 )
  497.         return_error(gs_error_rangecheck);    /* mode not available */
  498.     fb_dev->mode = mip;
  499.     gx_device_adjust_resolution(dev, mip->width, mip->height);
  500.     fb_dev->info.vesa.bios_set_page = info.win_func_ptr;
  501.     /* Reset the raster per the VESA info. */
  502.     fb_dev->raster = info.bytes_per_line;
  503.     return 0;
  504. }
  505. private int
  506. vesa_open(gx_device *dev)
  507. {    static const mode_info mode_table[] = {
  508.        {     640,  400, 0x100    },
  509.        {     640,  480, 0x101    },
  510.        {     800,  600, 0x103    },
  511.        {    1024,  768, 0x105    },
  512.        {    1280, 1024, 0x107    },
  513.        {    -1, -1, -1    }
  514.     };
  515.     int code = vesa_find_mode(dev, mode_table);
  516.     if ( code < 0 ) return code;
  517.     return svga_open(dev);
  518. }
  519.  
  520. /* Set the current display page. */
  521. private void
  522. vesa_set_page(gx_device_svga *dev, int pn, int wnum)
  523. {
  524. #if USE_ASM
  525. extern void vesa_call_set_page(P3(void (*)(P2(int, int)), int, int));
  526.     if ( dev->info.vesa.bios_set_page != NULL )
  527.         vesa_call_set_page(dev->info.vesa.bios_set_page, pn, wnum);
  528.     else
  529. #endif
  530.        {    registers regs;
  531.         regs.rshort.dx = pn;
  532.         regs.h.ah = 0x4f;
  533.         regs.h.al = 5;
  534.         regs.rshort.bx = wnum;
  535.         int86(0x10, ®s, ®s);
  536.        }
  537. }
  538.  
  539. /* ------ The ATI Wonder device ------ */
  540.  
  541. private dev_proc_open_device(atiw_open);
  542. private gx_device_procs atiw_procs = svga_procs(atiw_open);
  543. private int atiw_get_mode(P0());
  544. private void atiw_set_mode(P1(int));
  545. private void atiw_set_page(P3(gx_device_svga *, int, int));
  546. gx_device_svga gs_atiw_device =
  547.     svga_device(atiw_procs, "atiw", atiw_get_mode, atiw_set_mode, atiw_set_page);
  548.  
  549. /* Read the device mode */
  550. private int
  551. atiw_get_mode()
  552. {    registers regs;
  553.     regs.h.ah = 0xf;
  554.     int86(0x10, ®s, ®s);
  555.     return regs.h.al;
  556. }
  557.  
  558. /* Set the device mode */
  559. private void
  560. atiw_set_mode(int mode)
  561. {    registers regs;
  562.     regs.h.ah = 0;
  563.     regs.h.al = mode;
  564.     int86(0x10, ®s, ®s);
  565. }
  566.  
  567. /* Initialize the graphics mode. */
  568. private int
  569. atiw_open(gx_device *dev)
  570. {    /* Select the proper video mode */
  571.        {    static const mode_info mode_table[] = {
  572.            {     640,  400, 0x61    },
  573.            {     640,  480, 0x62    },
  574.            {     800,  600, 0x63    },
  575.            {    -1, -1, -1    }
  576.         };
  577.         int code = svga_find_mode(dev, mode_table);
  578.         if ( code < 0 ) return code;    /* mode not available */
  579.         fb_dev->info.atiw.select_reg = *(int *)MK_PTR(0xc000, 0x10);
  580.         return svga_open(dev);
  581.        }
  582. }
  583.  
  584. /* Set the current display page. */
  585. private void
  586. atiw_set_page(gx_device_svga *dev, int pn, int wnum)
  587. {    int select_reg = dev->info.atiw.select_reg;
  588.     byte reg;
  589.     disable();
  590.     outportb(select_reg, 0xb2);
  591.     reg = inportb(select_reg + 1);
  592.     outportb(select_reg, 0xb2);
  593.     outportb(select_reg + 1, (reg & 0xe1) + (pn << 1));
  594.     enable();
  595. }
  596.  
  597. /* ------ The Trident device ------ */
  598.  
  599. private dev_proc_open_device(tvga_open);
  600. private gx_device_procs tvga_procs = svga_procs(tvga_open);
  601. /* We can use the tseng_get/set_mode procedures. */
  602. private void tvga_set_page(P3(gx_device_svga *, int, int));
  603. gx_device_svga gs_tvga_device =
  604.     svga_device(tvga_procs, "tvga", atiw_get_mode, atiw_set_mode, tvga_set_page);
  605.  
  606. /* Initialize the graphics mode. */
  607. private int
  608. tvga_open(gx_device *dev)
  609. {       fb_dev->wnum_read = 1;
  610.     fb_dev->wnum_write = 0;
  611.     /* Select the proper video mode */
  612.        {    static const mode_info mode_table[] = {
  613.            {     640,  400, 0x5c        },
  614.            {     640,  480, 0x5d        },
  615.            {     800,  600, 0x5e        },
  616.            {     1024, 768, 0x62        },
  617.            {    -1, -1, -1      }
  618.         };
  619.         int code = svga_find_mode(dev, mode_table);
  620.         if ( code < 0 ) return code;      /* mode not available */
  621.         return svga_open(dev);
  622.        }
  623. }
  624.  
  625. /* Set the current display page. */
  626. private void
  627. tvga_set_page(gx_device_svga *dev, int pn, int wnum)
  628. {
  629.     /* new mode */
  630.     outportb(0x3c4, 0x0b);
  631.     inportb(0x3c4);
  632.  
  633.     outportb(0x3c4, 0x0e);
  634.     outportb(0x3c5, pn ^ 2);
  635. }
  636.  
  637. /* ------ The Tseng Labs ET3000/4000 device ------ */
  638.  
  639. private dev_proc_open_device(tseng_open);
  640. private gx_device_procs tseng_procs = svga_procs(tseng_open);
  641. /* We can use the tseng_get/set_mode procedures. */
  642. private void tseng_set_page(P3(gx_device_svga *, int, int));
  643. gx_device_svga gs_tseng_device =
  644.     svga_device(tseng_procs, "tseng", atiw_get_mode, atiw_set_mode, tseng_set_page);
  645.  
  646. /* Initialize the graphics mode. */
  647. private int
  648. tseng_open(gx_device *dev)
  649. {    fb_dev->wnum_read = 1;
  650.     fb_dev->wnum_write = 0;
  651.     /* Select the proper video mode */
  652.        {    static const mode_info mode_table[] = {
  653.            {     640,  350, 0x2d    },
  654.            {     640,  480, 0x2e    },
  655.            {     800,  600, 0x30    },
  656.            {     1024, 768, 0x38    },
  657.            {    -1, -1, -1    }
  658.         };
  659.         int code = svga_find_mode(dev, mode_table);
  660.         fb_ptr p0 = (fb_ptr)MK_PTR(regen, 0);
  661.         if ( code < 0 ) return code;    /* mode not available */
  662.         /* Figure out whether we have an ET3000 or an ET4000 */
  663.         /* by playing with the segment register. */
  664.         outportb(0x3cd, 0x44);
  665.         *p0 = 4;        /* byte 0, page 4 */
  666.         outportb(0x3cd, 0x40);
  667.         *p0 = 3;        /* byte 0, page 0 */
  668.         fb_dev->info.tseng.et_model = *p0;
  669.                     /* read page 0 if ET3000, */
  670.                     /* page 4 if ET4000 */
  671.         return svga_open(dev);
  672.        }
  673. }
  674.  
  675. /* Set the current display page. */
  676. private void
  677. tseng_set_page(gx_device_svga *dev, int pn, int wnum)
  678. {    /* The ET3000 has read page = 5:3, write page = 2:0; */
  679.     /* the ET4000 has read page = 7:4, write page = 3:0. */
  680.     int shift = dev->info.tseng.et_model;
  681.     int mask = (1 << shift) - 1;
  682.     if ( wnum ) pn <<= shift, mask <<= shift;
  683.     outportb(0x3cd, (inportb(0x3cd) & ~mask) + pn);
  684. }
  685.